package jgcp.client;

import java.net.Socket;
import java.util.Scanner;

import jgcp.common.Task;
import jgcp.common.TaskDescription;
import jgcp.common.TaskType;
import jgcp.common.network.Connection;
import jgcp.common.network.FileSender;
import jgcp.config.Configuration;
import jgcp.message.Message;
import jgcp.message.MessageType;
import jgcp.utils.Packer;

/**
 * 
 * @Date 29/05/2009
 * @author Jie Zhao (288654)
 * @version 1.0
 */
public class CmdClient {
	public static String prompt = "Command(@s): ";

	public static enum STATUS {
		NOT_CONNECTED, CONNECTED
	};

	public static STATUS status = STATUS.NOT_CONNECTED;
	private static Socket socket = null;
	private static Connection connection = null;
	public static String filename = "";
	
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);

		String temp = null;
		while (true) {
			try {
				System.out.print(getPrompt());
				temp = scanner.nextLine();
				String[] buffer = temp.split(" ");
				String cmd = buffer[0];
				if (cmd.equalsIgnoreCase("quit")) {
					if(connection != null)connection.getSocket().close();
					break;
				} else if (cmd.equalsIgnoreCase("help")) {
					printHelp();
				} else if (cmd.equalsIgnoreCase("connect")) {
					connect(buffer);
				} else if (cmd.equalsIgnoreCase("listworkers")) {
					sendMessage(MessageType.LISTWORKER);
				} else if (cmd.equalsIgnoreCase("submit")) {
					submitTask(buffer);
				} else if (cmd.equalsIgnoreCase("listtasks")) {
					sendMessage(MessageType.LISTTASKS);
				} else if (cmd.equalsIgnoreCase("status")) {
					sendMessageWithBody(MessageType.QUERYSTATUS, buffer[1]);
				} else if (cmd.equalsIgnoreCase("cancel")) {
					sendMessageWithBody(MessageType.CANCELTASK, buffer[1]);
				}
				else if(cmd.equalsIgnoreCase("getresult"))
				{
					filename = buffer[2];
					sendMessageWithBody(MessageType.GETRESULT,buffer[1]);
				}
				else {
					System.out
							.println("[Error]Command not recognized!Enter help to display the manual.");
				}

				Thread.sleep(1000);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	static void sendMessage(int messageType) throws Exception {
		if (checkConnection()) {
			Message msg = new Message();
			msg.setType(messageType);
			connection.writeData(msg.toByteArray());
		}
	}

	private static void sendMessageWithBody(int messageType, String messageBody)
			throws Exception {
		if (checkConnection()) {
			Message msg = new Message();
			msg.setType(messageType);
			msg.setMessageBody(messageBody);
			connection.writeData(msg.toByteArray());
		}
	}

	static void submitTask(String[] args) throws Exception {
		if (checkConnection()) {
			String filename = "" + System.currentTimeMillis() + ".zip";
			String workingFolder = Configuration.getInstance()
					.getClientTempfolder();
			TaskDescription td = new TaskDescription();
			Task t = new Task();
			t.setDescription(td);
			if (args.length >= 2) // exe|jar only
			{
				if (args[1].endsWith("exe")) {
					td.setType(TaskType.EXE);
				} else if (args[1].endsWith("jar")) {
					td.setType(TaskType.JAR);
				}
				td.setExefile(args[1]);
				if (args.length == 3) {
					td.setDataFile(args[2]);
				}
			} else {
				return;
			}
			String file = workingFolder + filename;
			Packer.packTask(t, file);
			FileSender<TaskDescription> sender = new FileSender<TaskDescription>(
					td, file);
			int port = sender.getPort();
			sender.start();
			Message m = new Message();
			m.setType(MessageType.SUBMITTASK);
			m.setMessageBody("" + port);
			connection.writeData(m.toByteArray());
		}
	}

	private static boolean checkConnection() {
		if (!isConnected()) {
			System.out
					.println("Not Connected. Please connect to master first.");
		}
		return isConnected();
	}

	static void connect(String[] buffer) throws Exception {
		if (!isConnected()) {
			String host = buffer[1];
			String port = buffer[2];
			String username = buffer[3];
			String password = buffer[4];
			socket = new Socket(host, Integer.parseInt(port));
			Message msg = new Message();
			msg.setType(MessageType.LOGIN);
			msg.setMessageBody(username + " " + password);
			socket.getOutputStream().write(msg.toByteArray());
			connection = new Connection();
			connection.setSocket(socket);
			new ClientMessageHandler(connection).start();
		}
	}

	public static void printHelp() {
		System.out.println("====== Supported Commands: ======");
		System.out.println("1.connect\t- Connect to master");
		System.out.println("--Format: connect host port username password");
		System.out.println("2.submit\t- Submit Tasks");
		System.out
				.println("--Format: submit exefile(*.exe or *.jar) [datafile]");
		System.out.println("3.listworkers\t- List all workers");
		System.out.println("4.listtasks\t- List all tasks");
		System.out.println("5.status\t- Query status of a task ");
		System.out.println("--Format: status taskId");
		System.out.println("6.cancel\t- Cancel a running task");
		System.out.println("--Format: cancel taskId");
		System.out.println("7.setAlgo");
		System.out
				.println("--Format: setAlgo 1-3(1=FCFS, 2=Earliest Deadline First(EDF), 3=EDF by Budget)");
		System.out.println("8.getResult");
		System.out.println("--Format:getResult taskid targetFile");
		System.out.println("9.quit\t- Close connection and exit");
		System.out.println("====== Help Ends. ======");
	}

	private static boolean isConnected() {
		switch (status) {
		case CONNECTED:
			return true;
		default:
			return false;
		}
	}

	private static String getPrompt() {
		return prompt.replaceAll("@s", status.name());
	}
}